/*
 * @Author: 信念D力量
 * @Github: https://www.github.com/fy2008
 * @Gitee: https://gitee.com/zsf90
 * @website: https://fy2008.github.io
 * @Date: 2021-02-10 18:05:00
 * @LastEditTime: 2021-02-10 21:25:38
 * @LastEditors: Please set LastEditors
 * @Copyright(C): 信念D力量 (freerealmshn@163.com)
 * All Rights Reserved.
 * ----------------------------------------------
 * @Description:
 * ----------------------------------------------
 * 数码管类型为共阳极，高电平灭，低电平亮
 *  *******
 * *   a    *
 * * f      * b
 * *        *
 * *    g   *
 *   ******
 * *        *
 * *        * c
 * * e      *
 * *   d    *
 * * ******   * dp
 * -------- 对应关系 ----------
 * dp g  f  e  d  c  b  a
 * 0  0  0  0  0  0  0  0
 * Q7 Q6 Q5 Q4 Q3 Q2 Q1 Q0
 *
 * 第一位进入的数据最终会到 Q7 的位置，我们应该先发送字节的高位
 * ----------------------------------------------------
 * IO 口
 * SDI  （D14）数据
 * SCLK （D12）脉冲，上升沿时，数据从移位寄存器转存到存储寄存器
 * LOAD （D13）输出控制，上升沿时，移位寄存器中的数据整体输出
 *
 * 第一个输入的位，是并行输出的最后一个位 | 最先进入弹夹的子弹，最后射出。
 */
#include "led_74hc595.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"

#define CLK_GPIO GPIO_NUM_12
#define SDI_GPIO GPIO_NUM_14
#define LOAD_GPIO GPIO_NUM_13

void hc595_init(void)
{
    gpio_reset_pin(CLK_GPIO);
    gpio_reset_pin(SDI_GPIO);
    gpio_reset_pin(LOAD_GPIO);

    gpio_set_direction(CLK_GPIO, GPIO_MODE_OUTPUT);
    gpio_set_direction(SDI_GPIO, GPIO_MODE_OUTPUT);
    gpio_set_direction(LOAD_GPIO, GPIO_MODE_OUTPUT);

    gpio_set_level(LOAD_GPIO, 0);
}

static void write_byte(uint8_t data)
{
    uint8_t temp = data;

    for (int i = 0; i < 8; i++)
    {
        gpio_set_level(CLK_GPIO, 0);
        if (temp & 0x80)
        {
            gpio_set_level(SDI_GPIO, 1);
        }
        else
        {
            gpio_set_level(SDI_GPIO, 0);
        }
        temp <<= 1;

        vTaskDelay(1 / portTICK_PERIOD_MS);
        gpio_set_level(CLK_GPIO, 1);
    }
}
/**
 *                  0     1     2     3     4     5     6     7     8     9     A     B     C     D     E    F     全灭
 *                  0     1     2     3     4     5     6     7     8     9     10    11    12    13    14   15    16
 */
uint8_t data[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e, 0xff};

void hc74595_display(uint32_t num)
{
    uint32_t qian = num / 1000;    // 解析后的千位数字
    uint32_t bai = num / 100 % 10; // 解析后的百位数字
    uint32_t shi = num / 10 % 10;  // 解析后的十位数字
    uint32_t ge = num % 10;        // 解析后的个位数字

    for (uint8_t j = 0; j < 4; j++)
    {
        switch (j)
        {
        case GE_BIT:
            // 个位
            write_byte(data[ge]); // SPI 输出
            break;
        case SHI_BIT:
            // 十位

            if (num > 9)
            {
                write_byte(data[shi]);
            }
            else
            {
                write_byte(data[16]);
            }
            break;
        case BAI_BIT:
            // 百位

            if (num > 99)
            {
                write_byte(data[bai]);
            }
            else
            {
                write_byte(data[16]);
            }
            break;
        case QIAN_BIT:
            // 千位
            if (num > 999)
            {
                write_byte(data[qian]);
            }
            else
            {
                write_byte(data[16]);
            }

            break;
        default:
            break;
        }
    } // end for

    /* 让锁存输出一个高电平脉冲 */
    gpio_set_level(LOAD_GPIO, 1);
    vTaskDelay(1 / portTICK_PERIOD_MS);
    gpio_set_level(LOAD_GPIO, 0);
}
